package com.hitqz.robot.biz.schedule;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.hitqz.robot.api.business.dto.*;
import com.hitqz.robot.api.business.enums.*;
import com.hitqz.robot.api.business.model.dto.FlowPatrolPreAndEndTicketsDto;
import com.hitqz.robot.api.common.entity.*;
import com.hitqz.robot.api.common.enums.SubscribeTopicEnum;
import com.hitqz.robot.api.dispatch.protocol.ProtocolEnum;
import com.hitqz.robot.biz.service.*;
import com.hitqz.robot.biz.websocket.util.BroadcastTopicUtil;
import com.hitqz.robot.camera.EquipmentFactory;
import com.hitqz.robot.common.core.util.R;
import com.hitqz.robot.driver.dto.robot.RobotCustomInfo;
import com.hitqz.robot.driver.model.IRobotPosDto;
import com.hitqz.robot.driver.model.PointDto;
import com.hitqz.robot.driver.parent.RobotDriverService;
import com.hitqz.robot.netty.service.Send2ServerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author xupkun
 * @date 2024/6/21
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class WsSendStatusSchedule {

    private final RobotService robotService;

    private final RobotDriverService robotDriverService;

    private final Send2ServerService send2ServerService;

    private final SysWarningService sysWarningService;

    private final TicketsService ticketsService;

    private final EquipmentFactory equipmentFactory;

    private final TicketsTaskService ticketsTaskService;

    private final RobotEquipmentService robotEquipmentService;

    private final ButtonService buttonService;

    /**
     * 由于调度系统需要更快的坐标数据，所以提高上报频率
     */
    @Scheduled(fixedRate = 300L)
    public void sendStatus(){
        //StopWatch stopWatch = new StopWatch();
        //stopWatch.start("takePictureComponent");
        IRobotPosDto iRobotPosDto = robotDriverService.getWebPos();
        if(iRobotPosDto != null) {
            Robot robot = robotService.getDefaultRobot();
            //log.info("currentStation : {}", iRobotPosDto.getCurrentStation());
            //if (robot.getDispatch() == 1) {
            //    // 调度上线的情况下，禁止其他的客户端之类的，抢占控制权，防止发生不可控制的意外
            //    robotDriverService.executeOtherCommand(RobotOtherCommandEnum.ROD_CONTROLLER, "");
            //}
            //stopWatch.stop();
            //log.info("get web use ：" + stopWatch.prettyPrint(TimeUnit.SECONDS));
            RobotClientSummaryDto dto = new RobotClientSummaryDto();
            //外设
            RobotEquipmentPanelDto robotEquipmentPanelDto = new RobotEquipmentPanelDto();
            List<RobotEquipment> list = robotEquipmentService.list(Wrappers.<RobotEquipment>lambdaQuery().eq(RobotEquipment::getIsPlay, 1));
            if (list != null && !list.isEmpty()) {
                //预览地址
                robotEquipmentPanelDto.setPlayUrls(list.stream().map(RobotEquipment::getPlayUrl).filter(StrUtil::isNotBlank).toList());
            }
            //外设按钮
            robotEquipmentPanelDto.setPanels(robotEquipmentService.getControlButtonList());
            dto.setLogicOnlineStatus(robot.getDispatch());
            dto.setEquipmentPanel(robotEquipmentPanelDto);
            RobotStatusDto robotStatusDto = new RobotStatusDto();

            // 顶升状态 判断
            if (RobotModelEnum.AGV.getFlag().equals(robot.getRobotModel())) {
                // 计算顶升状态




            }

            dto.setClientId(robot.getRobotSn());
            robotStatusDto.setName(robot.getRobotName());
            robotStatusDto.setSn(robot.getRobotSn());
            robotStatusDto.setIp(robot.getIpAddress());
            robotStatusDto.setOnlineStatus(Integer.valueOf(robot.getOnlineStatus()));
            robotStatusDto.setOnlineStatusStr(robot.getOnlineStatus().equals("1")? "在线": "离线");
            robotStatusDto.setErrorStatus(1);
            robotStatusDto.setErrorStatusStr("正常");
            robotStatusDto.setBattery(String.valueOf(iRobotPosDto.getBatteryLevel()));
            //robotStatusDto.setBattery("20.0");
            robotStatusDto.setVoltage(String.valueOf(iRobotPosDto.getVoltage()));
            robotStatusDto.setCurrent(String.valueOf(iRobotPosDto.getCurrent()));
            robotStatusDto.setCurrentDirection(iRobotPosDto.getCurrentDirection() == null ? "放电": iRobotPosDto.getCurrentDirection());
            robotStatusDto.setChargeStatus(iRobotPosDto.isCharging() ? 1: 0);
            robotStatusDto.setChargeStatusStr(iRobotPosDto.isCharging()? "充电中": "正常速度控制");
            robotStatusDto.setIsFull(iRobotPosDto.getFull());

            robotStatusDto.setNavStatus(iRobotPosDto.getNavStatus());
            robotStatusDto.setNavStatusStr(NavEnum.NAV_STATUS.get(iRobotPosDto.getNavStatus()));
            robotStatusDto.setTaskStatus(iRobotPosDto.getTaskStatus());
            robotStatusDto.setTaskStatusStr(iRobotPosDto.getTaskStatusStr());
            robotStatusDto.setTemperature(String.valueOf(iRobotPosDto.getTemperature()));

            robotStatusDto.setSpeed(String.valueOf(iRobotPosDto.getSpeed()));
            robotStatusDto.setWorkStatus(Integer.parseInt(robot.getWorkStatus()));
            robotStatusDto.setWorkStatusStr(WorkStatusEnum.CMD_ROBOT_STATUS.get(robot.getWorkStatus()).getDesc());
            robotStatusDto.setEmergencyStop(iRobotPosDto.isEmergency() ? 1: 0);
            robotStatusDto.setEmergencyStopStr(iRobotPosDto.isEmergency() ?  "急停触发": "未触发");

            dto.setStatus(robotStatusDto);
            RobotPositionDto robotPositionDto = new RobotPositionDto();
            robotPositionDto.setMapCode(robot.getMapCode());
            robotPositionDto.setUrl(iRobotPosDto.getUrl());
            robotPositionDto.setWebControlSpeed(iRobotPosDto.getWebControlSpeed());

            /**
             * 机器人像素位置
             */
            RobotLaserPosDto robotPixelPos = new RobotLaserPosDto();
            robotPixelPos.setYaw(Double.parseDouble(String.valueOf(iRobotPosDto.getPixelAngle())));
            robotPixelPos.setX(Double.parseDouble(String.valueOf(iRobotPosDto.getPixelX())));
            robotPixelPos.setY(Double.parseDouble(String.valueOf(iRobotPosDto.getPixelY())));
            robotPixelPos.setZ(0.0D);
            robotPositionDto.setPixelPos(robotPixelPos);

            /**
             * 机器人形式过的路径
             */
            ArrayList<RobotPosDto> passedPath = new ArrayList<>();
            for (PointDto pointDto : CollUtil.emptyIfNull(iRobotPosDto.getPassedPath())) {
                RobotPosDto robotPosDto = new RobotPosDto();
                robotPosDto.setX(pointDto.getX());
                robotPosDto.setY(pointDto.getY());
                passedPath.add(robotPosDto);
            }
            robotPositionDto.setPassedPath(passedPath);


            /**
             * 机器人激光位置
             */
            RobotLaserPosDto robotLaserPosDto = new RobotLaserPosDto();
            robotLaserPosDto.setYaw(Double.parseDouble(String.valueOf(iRobotPosDto.getAngle())));
            robotLaserPosDto.setX(Double.parseDouble(String.valueOf(iRobotPosDto.getX())));
            robotLaserPosDto.setY(Double.parseDouble(String.valueOf(iRobotPosDto.getY())));
            robotLaserPosDto.setZ(0.0D);
            // 最近的距离
            robotLaserPosDto.setNearPosCode(iRobotPosDto.getCurrentStation());
            robotLaserPosDto.setLastPosCode(iRobotPosDto.getLastStation());
            robotPositionDto.setLaserPos(robotLaserPosDto);

            /**
             * 二维码位置
             */
            RobotQRPosDto robotQRPosDto = new RobotQRPosDto();
            robotQRPosDto.setLabel("");
            robotQRPosDto.setAngle(0.0D);
            robotQRPosDto.setX(0.0D);
            robotQRPosDto.setY(0.0D);
            robotQRPosDto.setZ(0.0D);
            robotPositionDto.setQrCodePos(robotQRPosDto);
            RobotPosDto robotPosDto = new RobotPosDto();
            robotPosDto.setX(Double.parseDouble(String.valueOf(iRobotPosDto.getX())));
            robotPosDto.setY(Double.parseDouble(String.valueOf(iRobotPosDto.getY())));
            robotPosDto.setZ(0.0D);
            robotPositionDto.setMileage(robotPosDto);
            robotPositionDto.setLaser2D(Lists.newArrayList());
            robotPositionDto.setLaser3D("");
            dto.setPosition(robotPositionDto);
            RobotTaskDto robotTaskDto = new RobotTaskDto();
            RobotTransportTaskDto robotTransportTaskDto = new RobotTransportTaskDto();
            if (robot.getWorkStatus().equals(WorkStatusEnum.WORK.getCode())) {
                Tickets tickets = ticketsService.getOne(Wrappers.<Tickets>lambdaQuery()
                        .eq(Tickets::getStatus, TicketsStatusEnum.STATUS_EXECUTING.getCode())
                                .orderByDesc(Tickets::getId)
                        .last("limit 1"));
                if (tickets != null) {
                    robotTaskDto.setId(String.valueOf(tickets.getId()));
                    robotTaskDto.setName(tickets.getName());
                    robotTaskDto.setStartTime(DateUtil.format(tickets.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
                    robotTaskDto.setStatusStr("执行中");
                    if (robot.getRobotModel().equals(RobotModelEnum.AGV.getFlag()) && StrUtil.isNotBlank(tickets.getContent())) {
                        robotTaskDto.setType("3");
                        TicketsTask ticketsTask = ticketsTaskService.getOne(Wrappers.<TicketsTask>lambdaQuery()
                                .eq(TicketsTask::getTicketsId, tickets.getId())
                                .eq(TicketsTask::getStatus, TicketsStatusEnum.TICKETS_TASK_EXECUTING.getCode()).last(" limit 1")
                        );
                        FlowPatrolPreAndEndTicketsDto ticketsDto = JSONObject.parseObject(ticketsTask.getParseOrderParams()
                                , FlowPatrolPreAndEndTicketsDto.class);

                        String sourceName = Optional.ofNullable(ticketsDto.getModalData().get("sourcePosName"))
                                .orElse(ticketsDto.getModalData().get("sourcePosCode")).toString();
                        String targetName = Optional.ofNullable(ticketsDto.getModalData().get("targetPosName"))
                                .orElse(ticketsDto.getModalData().get("targetPosCode")).toString();
                        robotTransportTaskDto.setStartSite(sourceName);
                        robotTransportTaskDto.setTargetSite(targetName);
                    } else {
                        robotTransportTaskDto.setStartSite("");
                        robotTransportTaskDto.setTargetSite("");
                    }
                }
            } else {
                robotTaskDto.setId("");
                robotTaskDto.setName("");
                robotTaskDto.setType("");
                robotTaskDto.setStatus("");
                robotTaskDto.setStartTime("");
            }
            robotTaskDto.setTransportTask(robotTransportTaskDto);
            dto.setTask(robotTaskDto);
            RobotControlPanelDto robotControlPanelDto = new RobotControlPanelDto();

            // 使用方法
            List<Button> buttonsDb = buttonService.list(Wrappers.<Button>lambdaQuery().eq(Button::getObject, "robot").eq(Button::getIsShow, true));
            List<RobotControlButtonDto> buttons = BeanUtil.copyToList(buttonsDb, RobotControlButtonDto.class);
            robotControlPanelDto.setButtons(buttons);
            dto.setControlPanel(robotControlPanelDto);


            // 机器人报警
            List<RobotWarningDto> robotWarningDtos = Lists.newArrayList();
            List<SysWarning> sysWarnings = sysWarningService.list(Wrappers.<SysWarning>lambdaQuery().orderByDesc(SysWarning::getId)
                    .ne(SysWarning::getCode, "999")
                    .last("limit 10"));
            sysWarnings.stream().forEach(t-> {
                RobotWarningDto robotWarningDto = new RobotWarningDto();
                robotWarningDto.setType("0");
                robotWarningDto.setTitle(t.getContent());
                robotWarningDto.setContent(t.getContent());
                robotWarningDto.setTime(DateUtil.format(t.getWarningTime(), "yyyy-MM-dd HH:mm:ss"));
                robotWarningDto.setLevel(1);
                robotWarningDto.setPath(t.getPaths());
                robotWarningDtos.add(robotWarningDto);
            });
            dto.setWarning(robotWarningDtos);

            //  巡检报警
            List<SysWarning> errorChecks = sysWarningService.list(Wrappers.<SysWarning>lambdaQuery().orderByDesc(SysWarning::getId)
                            .eq(SysWarning::getCode, "999")
                    .last("limit 10"));
            List<RobotWarningDto> errors = Lists.newArrayList();
            errorChecks.stream().forEach(t-> {
                RobotWarningDto robotWarningDto = new RobotWarningDto();
                robotWarningDto.setType("0");
                robotWarningDto.setTitle(t.getContent());
                robotWarningDto.setContent(t.getContent());
                robotWarningDto.setTime(DateUtil.format(t.getWarningTime(), "yyyy-MM-dd HH:mm:ss"));
                robotWarningDto.setLevel(1);
                robotWarningDto.setPath(t.getPaths());
                errors.add(robotWarningDto);
            });
            dto.setErrorChecks(errors);

            // 其他状态信息
            RobotOtherInfoDto robotOtherInfoDto = new RobotOtherInfoDto();
            robotOtherInfoDto.setRobotLength(robot.getRobotLength());
            robotOtherInfoDto.setRobotWidth(robot.getRobotWidth());
            robotOtherInfoDto.setRobotAngleLength(robot.getRobotAngleLength());
            dto.setOtherInfo(robotOtherInfoDto);
            List<RobotCustomInfo> robotCustomInfos = robotDriverService.getCustomInfo();
            if (CollUtil.isNotEmpty(robotCustomInfos)) {
                List<RobotCustomInfoDto> robotCustomInfoDtos = Lists.newArrayList();
                robotDriverService.getCustomInfo().stream().forEach(t-> {
                    robotCustomInfoDtos.add(new RobotCustomInfoDto(t.getLabel(), t.getValue(),t.getKey()));
                });
                robotOtherInfoDto.setCustomInfos(robotCustomInfoDtos);
            }
            String data = JSONObject.toJSONString(dto);
            if (log.isDebugEnabled()) {
                log.debug("send data to robot" + data );
            }
            try {
                // 传给前端
                BroadcastTopicUtil.broadcastMessageByTopic(SubscribeTopicEnum.ROBOT_INFO.getTopic(), data );
            } catch (Exception e) {

            }
            try {
                // 发送给服务端, 保证传给服务端，不然无法执行任务
                send2ServerService.send2ServerData(Integer.valueOf(ProtocolEnum.ROBOT_SUMMARY.getCmd()), JSONObject.toJSONString(dto));
            } catch (Exception e) {

            }
        }
    }

    /**
     * 报警信息
     */
    @Scheduled(fixedRate = 3000L)
    public void sendWarning(){
        SysWarning sysWarning = sysWarningService.getOne(Wrappers.<SysWarning>lambdaQuery()
                .eq(SysWarning::getStatus, 0)
                .orderByDesc(SysWarning::getId)
                .last("limit 1"));
        RobotWarningDto robotWarningDto = null;
        if (sysWarning != null) {
            robotWarningDto = new RobotWarningDto();
            robotWarningDto.setId(sysWarning.getId());
            robotWarningDto.setType("0");
            robotWarningDto.setTitle(sysWarning.getTitle());
            robotWarningDto.setContent(sysWarning.getContent());
            robotWarningDto.setTime(DateUtil.format(sysWarning.getWarningTime(), "yyyy-MM-dd HH:mm:ss"));
            robotWarningDto.setLevel(1);
            robotWarningDto.setPath(sysWarning.getPaths());
        }else{
            robotWarningDto = new RobotWarningDto();
            robotWarningDto.setId(-1L);
        }
        BroadcastTopicUtil.broadcastMessageByTopic(SubscribeTopicEnum.ROBOT_WARNING.getTopic(), JSONObject.toJSONString(robotWarningDto));
    }


    /**
     * 挂轨--语音对讲-进行页面通知
     */
    @Scheduled(fixedRate = 3000L)
    public void sendSpeak(){
        R result = robotDriverService.executeOtherCommand(RobotOtherCommandEnum.SPEAK_REQUEST, "");
        BroadcastTopicUtil.broadcastMessageByTopic(SubscribeTopicEnum.ROBOT_SPEAK_REQUEST.getTopic(), JSONObject.toJSONString(result));
    }



    //@Scheduled(fixedRate = 2000L)
    //public void sendEquipmentStatus(){
    //    List<RobotEquipment> robotEquipments = robotEquipmentService.list();
    //    for (RobotEquipment robotEquipment : robotEquipments) {
    //        IEquipmentService service = equipmentFactory.getServiceByBrand(robotEquipment.getBrand());
    //        QueryParamsDto queryParamsDto = new QueryParamsDto();
    //        queryParamsDto.setUsername(robotEquipment.getUsername());
    //        queryParamsDto.setPassword(robotEquipment.getPassword());
    //        queryParamsDto.setPort(robotEquipment.getPort());
    //        queryParamsDto.setIp(robotEquipment.getIp());
    //        queryParamsDto.setChannel(robotEquipment.getChannel());
    //        if (!NetUtil.ping(robotEquipment.getIp())){
    //            continue;
    //        }
    //        if (service != null) {
    //            BroadcastTopicUtil.broadcastMessageByRandomId(
    //                    robotEquipment.getId().intValue(), SubscribeTopicEnum.ROBOT_EQUIPMENT_STATUS,
    //                    JSONObject.toJSONString(service.getEquipmentParams(queryParamsDto)));
    //        }
    //    }
    //
    //}

    /**
     * 挂轨--语音对讲-进行页面通知
     */
    //@Scheduled(fixedRate = 1000L)
    //public void realManArmStatus(){
    //    IEquipmentService service = equipmentFactory.getServiceByBrand(BrandEnum.REALMAN.getEnStr());
    //    if (null == service) {
    //        return;
    //    }
    //    RobotEquipment equipment = robotEquipmentService.getOne(Wrappers.lambdaQuery(RobotEquipment.class)
    //            .eq(RobotEquipment::getBrand, BrandEnum.REALMAN.getEnStr()));
    //    if (null == equipment) {
    //        return;
    //    }
    //    QueryParamsDto queryParamsDto = new QueryParamsDto();
    //    queryParamsDto.setIp(equipment.getIp());
    //    queryParamsDto.setPort(equipment.getPort());
    //    try {
    //        IEquipmentCmdResult result = service.executeCmd(queryParamsDto, true, EquipmentCmdEnum.GET_CURRENT_ARM_STATE, null);
    //        send2ServerService.send2ServerData((int) ProtocolEnum.ROBOT_REAL_MAN_ARM_STATUS.getCmd(), JSONObject.toJSONString(result));
    //    } catch (Exception e) {
    //        log.error("获取瑞尔曼机械臂状态失败", e);
    //    }
    //}






}
